using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;

using System.Security.Permissions;
using System.Threading;

using WMOSSExperts.WebControls;

namespace WMOSSExperts.Fields
{
    /// <summary>
    /// This reverseLookupField is built to display related sourceList from reverse lookup
    /// </summary>
    [CLSCompliant(false), SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
    public class RelatedLookupLinksField : SPFieldBoolean
    {
        #region "Constructors"
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="fields"></param>
        /// <param name="fieldName"></param>
        public RelatedLookupLinksField(SPFieldCollection fields, String fieldName) : base(fields, fieldName) { }

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="fields"></param>
        /// <param name="typeName"></param>
        /// <param name="displayName"></param>
        public RelatedLookupLinksField(SPFieldCollection fields, String typeName, String displayName) : base(fields, typeName, displayName) { }
        #endregion

        #region "Private members"
        /// <summary>
        /// The name of the custom property in the property schema
        /// </summary>
        private const String kLookupLinks = "LookupLinks";
        
        /// <summary>
        /// The related lists linked to this current sourceList
        /// </summary>
        private SortedList<Guid, RelatedLookupLinksValue> relatedLinks;

        /// <summary>
        /// The string to store related lookup links
        /// </summary> 
        private String lookupLinks = String.Empty;
        #endregion

        #region "Override and Events handlers"
        /// <summary>
        /// Call update after a reverseLookupField is added to save custom properties 
        /// </summary>
        /// <param name="op"></param>
        public override void OnAdded(SPAddFieldOptions op)
        {
            base.OnAdded(op);
            this.Update();
        }

        /// <summary>
        /// set custom property values before update the reverseLookupField in Database
        /// </summary>
        public override void Update()
        {
            this.SetFieldProperties(); 
            base.Update();

            this.CleanNamedThreadData();
        }

        /// <summary>
        /// Gets the rendering control associated to this reverseLookupField
        /// </summary>
        public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
        {
            [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
            get
            {
                BaseFieldControl fieldControl = new RelatedLookupLinkControl();
                fieldControl.FieldName = this.InternalName;
                return fieldControl;
            }
        }
        #endregion

        

       

        #region "Field Properties"

        /// <summary>
        /// Gets or sets the related fields
        /// </summary>
        private String LookupLinks
        {
            get
            {
                if (String.IsNullOrEmpty(lookupLinks))
                {
                    lookupLinks = (String)FieldHelper.GetCurrentPropertyValue(this, kLookupLinks);
                }
                return lookupLinks;
            }
            set
            {
                lookupLinks = value;
                FieldHelper.SetNamedThreadData(kLookupLinks, value);
            }
        }

       #endregion

        #region "Manage internal fields attributes & property schema fields"

        /// <summary>
        /// Set the lookup link value from thread data
        /// </summary>
        private void SetFieldProperties()
        {
            base.SetCustomProperty(kLookupLinks, FieldHelper.GetCurrentPropertyValue(this,kLookupLinks));
        }

        /// <summary>
        /// Clean thread data
        /// </summary>
        private void CleanNamedThreadData()
        {
            Thread.FreeNamedDataSlot(kLookupLinks);
        }

        #endregion

        #region "Lookup Links management"

        /// <summary>
        /// Add a lookup link configuration
        /// </summary>
        /// <param name="reverseLookupId"></param>
        /// <param name="viewId"></param>
        /// <param name="childList"></param>
        /// <param name="displayChildItems"></param>
        public void AddLookupLink(Guid reverseLookupId, Guid viewId, String childList, Boolean displayChildItems)
        {
            //Verifiy if the reverseLookup exists
            RelatedLookupLinksValue link;
            if (!this.RelatedLinks.TryGetValue(reverseLookupId, out link))
            {
                if (!String.IsNullOrEmpty(this.LookupLinks)) this.LookupLinks += ";##;";
                String newLink = String.Format("{0};#;{1};#;{2};#;{3}", reverseLookupId, viewId, childList, displayChildItems);
                this.LookupLinks += newLink;
                this.RelatedLinks.Add(reverseLookupId, new RelatedLookupLinksValue(newLink));
            }
        }

        /// <summary>
        /// Remove a link configuration
        /// </summary>
        /// <param name="reverseLookupId"></param>
        public void RemoveLookupLink(Guid reverseLookupId)
        {
            //Verifiy if the reverseLookup exists
            RelatedLookupLinksValue linkFound;
            if (this.RelatedLinks.TryGetValue(reverseLookupId, out linkFound))
            {
                this.RelatedLinks.Remove(reverseLookupId);
                String newLinks = String.Empty;
                foreach (RelatedLookupLinksValue link in this.RelatedLinks.Values)
                {
                    String newLink = String.Format("{0};#;{1};#;{2};#;{3}", link.ReverseLookupId,
                                     link.FilteredViewId,
                                     link.ChildList,
                                     link.DisplayChildItems);
                    if (!String.IsNullOrEmpty(newLinks)) newLinks += ";##;";
                    newLinks += newLink;
                }
                this.LookupLinks = newLinks;
            }
        }


        /// <summary>
        /// Gets the related lists linked to this current sourceList
        /// </summary>
        private SortedList<Guid, RelatedLookupLinksValue> RelatedLinks
        {
            get
            {
                if (relatedLinks == null)
                {
                    relatedLinks = new SortedList<Guid,RelatedLookupLinksValue>();
                    List<RelatedLookupLinksValue> relatedLists = this.GetRelatedLists(true);
                    foreach (RelatedLookupLinksValue link in relatedLists)
                    {
                        relatedLinks.Add(link.ReverseLookupId, link);
                    }
                }
                return relatedLinks;
            }
        }

        /// <summary>
        /// Gets the number of related lists linked to this curent sourceList
        /// </summary>
        public Int32 RelatedLinksCount
        {
            get
            {
                return this.RelatedLinks.Count;
            }
        }

        /// <summary>
        /// Gets related lists which are linked to this current sourceList
        /// </summary>
        /// <param name="includeInactivateList"></param>
        /// <returns></returns>
        public List<RelatedLookupLinksValue> GetRelatedLists(Boolean includeInactivateList)
        {
            List<RelatedLookupLinksValue> relatedLists = new List<RelatedLookupLinksValue>();
            if (!String.IsNullOrEmpty(this.LookupLinks))
            {
                String[] links = this.LookupLinks.Split(new String[] { ";##;" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (String link in links)
                {
                    RelatedLookupLinksValue value = new RelatedLookupLinksValue(link);
                    if(value.DisplayChildItems  | includeInactivateList)relatedLists.Add(value);
                }
            }
            return relatedLists;
        }

        public void SetDisplayLists(SortedList<Guid, Boolean> newConfiguration)
        {
            if (newConfiguration == null) return;

            String newLinks = String.Empty;
            foreach (RelatedLookupLinksValue link in this.RelatedLinks.Values)
            {
                //Try to get the item fron newConfiguration
                Boolean display = false;
                newConfiguration.TryGetValue(link.ReverseLookupId, out display);

                String newLink = String.Format("{0};#;{1};#;{2};#;{3}", link.ReverseLookupId,
                                    link.FilteredViewId,
                                    link.ChildList,
                                    display);
                if (!String.IsNullOrEmpty(newLinks)) newLinks += ";##;";
                newLinks += newLink;
            }
            this.LookupLinks = newLinks;
            relatedLinks = null;
        }

        #endregion
    }
}
